package com.example.analysis.utils;

import org.apache.commons.math3.distribution.FDistribution;
import java.util.List;

// 单因素方差分析
public class OneWayAnova {
    // 计算p值，（p < 0.05，差异显著）
    public static double calculateANOVAPValue(List<double[]> groups,Double fValue) {
        if(fValue == null)
            // 1. 计算ANOVA的F值
            fValue = calculateANOVAFValue(groups);
        // 2.计算自由度
        int dfBetween = groups.size() - 1;
        int dfWithin = OneWayAnova.totalSampleSize(groups) - groups.size();

        // 3.计算p值（依赖Apache Commons Math）
        FDistribution fDistribution = new FDistribution(dfBetween, dfWithin);
        return 1 - fDistribution.cumulativeProbability(fValue);
    }
    // 计算ANOVA的F值
    public static double calculateANOVAFValue(List<double[]> groups) {
        double grandMean = calculateGrandMean(groups); // 总体均值
        double ssb = calculateSSB(groups, grandMean); // 组间平方和
        double ssw = calculateSSW(groups);            // 组内平方和

        int dfBetween = groups.size() - 1;
        int dfWithin = totalSampleSize(groups) - groups.size();

        return (ssb / dfBetween) / (ssw / dfWithin);
    }

    // 计算总均值
    private static double calculateGrandMean(List<double[]> groups) {
        double totalSum = 0;
        int totalSize = 0;
        for (double[] group : groups) {
            for (double x : group) totalSum += x;
            totalSize += group.length;
        }
        return totalSum / totalSize;
    }

    // 计算组间平方和 (SSB)
    private static double calculateSSB(List<double[]> groups, double grandMean) {
        double ssb = 0;
        for (double[] group : groups) {
            double groupMean = ComCalcUtils.calcMean(group);
            ssb += group.length * Math.pow(groupMean - grandMean, 2);
        }
        return ssb;
    }

    // 计算组内平方和 (SSW)
    private static double calculateSSW(List<double[]> groups) {
        double ssw = 0;
        for (double[] group : groups) {
            double groupMean = ComCalcUtils.calcMean(group);
            for (double x : group) {
                ssw += Math.pow(x - groupMean, 2);
            }
        }
        return ssw;
    }

    // 计算总样本量
    public static int totalSampleSize(List<double[]> groups) {
        int size = 0;
        for (double[] group : groups) size += group.length;
        return size;
    }
}
